<?php

use app\Redis;

/************************************************************
 * Copyright (C), 1993, Dacelve. Tech., Ltd.
 * FileName : server.php
 * Author   : Lizhijian
 * Version  : 1.0
 * Date     : 2018/1/15 9:47
 * Description   :命令行启动本文件作为服务器端
 * Function List :
 * History  :
 * <author>    <time>    <version >    <desc>
 * Lizhijian   2018/1/15   1.0          init
 ***********************************************************/
require __DIR__.'/../app/Server.php'; //协议包应用类
require __DIR__.'/../app/Redis.php'; //Redis应用类

//可承载1000连接左右（最高3800，待优化到3000人）

//用户信息表
$userTable = new swoole_table(1024);
$userTable->column('cmd', swoole_table::TYPE_STRING, 64);
$userTable->column('userId', swoole_table::TYPE_INT, 64);
$userTable->column('room', swoole_table::TYPE_INT, 64);
$userTable->column('group', swoole_table::TYPE_INT, 4);
$userTable->column('userName', swoole_table::TYPE_STRING, 64);
$userTable->column('headImg', swoole_table::TYPE_STRING, 128);
$userTable->column('clientId', swoole_table::TYPE_INT, 4);
$userTable->column('type', swoole_table::TYPE_INT, 4);
$userTable->create();

//Server::daemonize();//切换为守护进程

//配置数组
$config = [
    'heartbeat_check_interval' => 10,
    'heartbeat_idle_time' => 20,
    'ssl_cert_file' => '/usr/local/nginx/conf/cert/www_phpyd_com.crt',
    'ssl_key_file' => '/usr/local/nginx/conf/cert/www_phpyd_com.key',
    'log_file' => 'swoole.log',
    'worker_num' => 1
    //    'daemonize ' => 1
];
//创建websocket服务器对象
$server = new swoole_websocket_server('0.0.0.0', 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set($config);

$server->userTable = $userTable;
//开始
$server->on('open', function (swoole_websocket_server $server, $request) {
    //定时任务：检测心跳
    $server->tick(10000, function () use ($server) {
        $closeFdArr = $server->heartbeat(false);
        foreach ($closeFdArr as $fd) {
            $server->close($fd);
            var_dump($fd);
            $server->userTable->del($fd);
        }
    });
    //初始化应用类
    Server::__init($server);
});
//收到客户端消息
$server->on('message', function (swoole_websocket_server $server, $frame) {
    var_dump($frame->data);
    $data = Server::check($frame->data); //检查收到的包是否正确
    if ($data['code'] == Server::OK_DATA_STATUS) {
        //消息分类处理
        switch ($data['data']['cmd']) {
            //获取现有协议包
            case 'getPackList':
                $server->push($frame->fd, Server::back(Server::OK_DATA_MSG, Server::getPackList()));
                break;
            //普通消息
            case 'msg':
                //是否被禁言
                Redis::$dbindex = 2;
                $res = \app\Redis::get($data['data']['userId']);
                if ($res) {
                    $data['data']['cmd'] = 'speak';
                    $data['data']['msg'] = Server::ERROR_SPEAK;
                    Server::sendToOne((int) $data['data']['srcClientId'], $data['data'], '', Server::ERROR_SPEAK_STATUS);
                    break;
                }
                switch ($data['data']['type']) {
                    case 0://房间内广播
                        Server::sendToRoom($data['data'], $data['data']['room']);
                        break;
                    case 1://组播
                        Server::sendToGroup($data['data'], $data['data']['room'], $data['data']['group']);
                        break;
                    case 2://互播
                    case 3://OA消息通知
                        $srcClientId = (int) $data['data']['srcClientId'];
                        $toClientId = (int) $data['data']['toClientId'];
                        $srcUserInfo = $server->userTable[$srcClientId];
                        $toUserInfo = $server->userTable[$toClientId];

                        $msg = $data['data']['msg'];
                        if ($data['data']['type'] != 3 && $data['data']['room'] != 10000) { //不是OA房间
                            $msg = "@{$toUserInfo['userName']}：{$msg}";
                        }
                        $data['data']['msg'] = $msg;
                        Server::sendToOne($srcClientId, $data['data']);

                        $data['data']['userName'] = $srcUserInfo['userName'];
                        $data['data']['headImg'] = $srcUserInfo['headImg'];
                        Server::sendToOne($toClientId, $data['data']);
                        break;
                }
                break;
            case 'speak'://禁言
                //修改该用户发言权限
                Redis::$dbindex = 2;
                \app\Redis::set($data['data']['notAllowUserId'], $data['data']['data'], $data['data']['time']);
                //发给被禁言人和房间所有人
                $data['data']['msg'] = Server::ERROR_SPEAK;
                Server::sendToOne($data['data']['toClientId'], $data['data']);
                //返回数据
                $srcUserInfo = $server->userTable[$data['data']['srcClientId']];
                $toUserInfo = $server->userTable[$data['data']['toClientId']];
                $data['data']['cmd'] = 'msg';
                $data['data']['userId'] = $toUserInfo['userId'];
                $data['data']['type'] = $toUserInfo['type'];
                $data['data']['msg'] = $toUserInfo['userName'].'已被'.$srcUserInfo['userName'].'禁言'.$data['data']['time'].'秒';
                Server::sendToRoom($data['data'], $data['data']['room']);
                break;
            case 'gift'://送礼
                //发给被送礼人和房间所有人
                Server::sendToOne($data['data']['toClientId'], $data['data']);
                //返回数据
                $srcUserInfo = $server->userTable[$data['data']['srcClientId']];
                $toUserInfo = $server->userTable[$data['data']['toClientId']];
                $data['data']['cmd'] = 'msg';
                $data['data']['msg'] = "{$srcUserInfo['userName']}送了{$data['data']['data']} X {$data['data']['number']} 给{$toUserInfo['userName']}";
                Server::sendToRoom($data['data'], $data['data']['room']);
                break;
            case 'kick'://踢出
                //发给被踢出人和房间所有人
                $data['data']['msg'] = '你已被管理员踢出!';
                Server::sendToOne($data['data']['toClientId'], $data['data']);
                //返回数据
                $srcUserInfo = $server->userTable[$data['data']['srcClientId']];
                $toUserInfo = $server->userTable[$data['data']['toClientId']];
                $data['data']['cmd'] = 'msg';
                $data['data']['msg'] = "{$toUserInfo['userName']}被{$srcUserInfo['userName']}踢出了";
                Server::sendToRoom($data['data'], $data['data']['room']);

                //记录登陆状态
                if($server->userTabl['type'] == 1){
                    Redis::$dbindex = 2;
                    Redis::set('swoole-login-status-'.$server->userTable['userId'], 'logout');
                }
                break;
            //心跳
            case 'ping':
                break;
            //登录，加入$userInfo
            case 'login':
                //用户
                if ($data['data']['type']) {
                    //从Redis或数据库取
                    Redis::$dbindex = 2;
                    $info = Redis::get('swoole-userid-'.$data['data']['userId']);
                    $info = '';
                    if (!$info) {
                        if ($data['data']['room'] == 10000) {
                            $info = Server::find("SELECT nickname,avatar FROM fa_admin WHERE id = {$data['data']['userId']}");
                        } else {
                            $info = Server::find("SELECT nickname,avatar FROM fa_user WHERE id = {$data['data']['userId']}");
                        }
                        if (!$info['avatar'] || !$info['nickname']) {
                            Server::sendError($frame->fd, '用户信息获取失败！', $info);
                            break;
                        }
                        Redis::$dbindex = 2;
                        Redis::set('swoole-userid-'.$data['data']['userId'], $info, 86400);
                    }

                    $headImg = 'https://my-aliyun-test.oss-cn-shenzhen.aliyuncs.com/'.$info['avatar'];
                    $userName = $info['nickname'];

                    //更新登陆状态
                    Redis::$dbindex = 2;
                    Redis::set('swoole-login-status-'.$data['data']['userId'], 'login');
                }

                //游客
                else {
                    $headImg = Server::VISITOR_HEAD[rand(0, 4)];
                    $userName = Server::VISITOR_NAME.$data['data']['userId'];
                }
                $userInfo = [
                    'cmd' => 'login',
                    'userId' => $data['data']['userId'],
                    'room' => $data['data']['room'],
                    'group' => $data['data']['group'],
                    'userName' => $userName,
                    'headImg' => $headImg,
                    'clientId' => $frame->fd,
                    'type' => $data['data']['type'],
                ];
                $server->userTable[$frame->fd] = $userInfo;

                Server::sendUserListToLoginer($frame->fd); //给登录者发送用户列表
                Server::sendUserList($frame->fd); //给其他用户发送登录者信息
                Server::sendLoginToRoom($userInfo, $userInfo['room']); //发送登录用户信息


                break;
            //全站公告
            case 'ad':
                Server::sendToAll($data['data']);
                break;
            //获取用户列表
            case 'getUsrList':
                Server::sendUserListToLoginer($frame->fd); //给登录者发送用户列表
                break;
        }
    } else {
        //验证失败
//        Server::record($data);
        $server->push($frame->fd, Server::back($data['msg'], $data['data'], 0, Server::ERROR_DATA_STATUS));
    }
});
//关闭连接
$server->on('close', function ($server, $fd) {
//    echo 'close'."\n";
    $userInfo = $server->userTable[$fd];
    $server->after(1000, function () use ($server, $userInfo, $fd) {
        Server::sendLoginToRoom([
            'cmd' => 'logout',
            'msg' => $userInfo['userName'],
            'userId' => $userInfo['userId'],
            'srcClientId' => $fd,
            'toClientId' => 0,
            'room' => $userInfo['room'],
            'group' => $userInfo['group'],
            'type' => $userInfo['type'],
            'data' => [],
        ], $userInfo['room']);
        //记录登陆状态
        if($userInfo['type'] == 1){
            Redis::$dbindex = 2;
            Redis::set('swoole-login-status-'.$userInfo['userId'], 'logout');
        }
    });

    //删除信息
    $server->userTable->del($fd);
});
//服务器启动
$server->start();
